package com.durian.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.durian.config.ServiceException;
import com.durian.domain.DTO.*;
import com.durian.domain.VO.ObsOrderBookListVO;
import com.durian.domain.VO.ObsOrderBookVO;
import com.durian.domain.VO.ObsOrderVO;
import com.durian.domain.entity.*;
import com.durian.enums.AddressStatus;
import com.durian.enums.OrderStatus;
import com.durian.mapper.*;
import com.durian.service.IObsOrderService;
import com.durian.utils.PageInfoResult;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * <p>
 * 订单表 服务实现类
 * </p>
 *
 * @author Durian
 * @since 2023-11-23
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ObsOrderServiceImpl extends ServiceImpl<ObsOrderMapper, ObsOrder> implements IObsOrderService {

    @Value("${default.pageNum}")
    private Integer pageNum;

    @Value("${default.pageSize}")
    private Integer pageSize;

    private final ObsUserMapper userMapper;

    private final ObsOrderMapper orderMapper;

    private final ObsOrderBookMapper orderBookMapper;

    private final ObsBookMapper bookMapper;

    private final ObsAddressMapper addressMapper;

    @Override
    @Transactional(propagation = Propagation.SUPPORTS)
    public PageInfoResult<ObsOrderVO> listOrder(ObsDefaultListDTO defaultListDTO) {

        //String searchMessage = defaultListDTO.getSearchMessage();
        Integer pageNum = defaultListDTO.getPageNum();
        Integer pageSize = defaultListDTO.getPageSize();

        // 检查分页页码和大小
        if (ObjectUtils.isNull(pageNum)) {
            pageNum = this.pageNum;
        }
        if (ObjectUtils.isNull(pageSize)) {
            pageSize = this.pageSize;
        }

        // 进行分页查询
        PageInfo<ObsOrderVO> pageInfo = PageHelper.startPage(pageNum, pageSize)
                .doSelectPageInfo(() ->
                        orderMapper.listOrder(defaultListDTO)
                );

        // 优化分页数据
        return PageInfoResult.of(pageInfo);
    }

    @Override
    @Transactional(propagation = Propagation.SUPPORTS)
    public List<ObsOrderVO> listUserOrder(ObsOrderListOnUserDTO listOnUserDTO) {

        Long userId = listOnUserDTO.getUserId();

        // 判断用户是否存在
        LambdaQueryWrapper<ObsUser> userExistWrapper = new LambdaQueryWrapper<ObsUser>()
                .select(ObsUser::getUserId)
                .eq(ObsUser::getUserId, userId);

        if (!userMapper.exists(userExistWrapper)) {
            throw new ServiceException("用户不存在");
        }

        // 根据查询条件获取订单信息
        List<ObsOrderBookListVO> orderVOList = orderMapper.listOrderOnUser(listOnUserDTO);

        // 过滤获取不重复的orderId的集合
        List<Long> orderIds = orderVOList.stream()
                .map(ObsOrderBookListVO::getOrderId)
                .distinct()
                .collect(Collectors.toList());

        List<ObsOrderVO> orderList = new ArrayList<>();

        orderIds.forEach(id -> {

            // 过滤重复的订单信息,并返回第一个元素
            Optional<ObsOrderVO> first = orderVOList
                    .stream()
                    .filter(orderBook -> Objects.equals(orderBook.getOrderId(), id))
                    .distinct()
                    .map(orderBook -> {
                        ObsOrderVO orderVO1 = new ObsOrderVO();
                        BeanUtils.copyProperties(orderBook, orderVO1);
                        return orderVO1;
                    }).findFirst();
            ObsOrderVO orderVO = new ObsOrderVO();
            // 先判断是否不为空，然后获取订单VO
            if (first.isPresent()) {
                orderVO = first.get();
            }

            // 对VO过滤操作，然后添加书籍VO
            List<ObsOrderBookVO> orderBookList = orderVOList
                    .stream()
                    .filter(order -> Objects.equals(order.getOrderId(), id))
                    .map(order -> {
                        ObsOrderBookVO orderBookVO = new ObsOrderBookVO();
                        BeanUtils.copyProperties(order, orderBookVO);
                        return orderBookVO;
                    }).collect(Collectors.toList());
            orderVO.setBookList(orderBookList);

            orderList.add(orderVO);
        });

        // 返回处理过后的订单信息集合
        return orderList;
    }

    @Override
    @Transactional
    public void addOrder(ObsOrderAddDTO orderAddDTO) {

        // 创建订单实体
        ObsOrder obsOrder = new ObsOrder();
        // 从DTO中获取数据
        BeanUtils.copyProperties(orderAddDTO, obsOrder);
        Long userId = orderAddDTO.getUserId();
        Long addressId = orderAddDTO.getAddressId();
        List<ObsOrderBookAddDTO> bookList = orderAddDTO.getBookList();


        // 检查用户是否存在
        userIsExist(userId);

        // 获取订单总价
        Double orderPrice = calculateOrderPrice(bookList);

        // 设置订单总价
        obsOrder.setOrderPrice(orderPrice);

        // 获取收货地址
        ObsAddress address = getAddress(addressId, userId);

        // 将地址信息放入订单实体中
        BeanUtils.copyProperties(address, obsOrder);

        // 添加订单
        int insertOrder = orderMapper.insert(obsOrder);
        if (insertOrder != 1) {
            log.error("数据库未知：{} = orderMapper.insert({})", insertOrder, obsOrder);
            throw new ServiceException("系统错误");
        }
        // 获取添加后订单的id
        Long orderId = obsOrder.getOrderId();

        // 添加订单书籍关联表的数据
        bookList.forEach(bookDTO -> {
            // 创建订单书籍关联实体,并添加数据
            ObsOrderBook orderBook = new ObsOrderBook();
            BeanUtils.copyProperties(bookDTO, orderBook);
            orderBook.setOrderId(orderId);

            // 添加订单书籍关联表记录
            int insertOrderBook = orderBookMapper.insert(orderBook);
            if (insertOrderBook != 1) {
                log.error("数据库未知：{} = orderBookMapper.insert({})", insertOrderBook, orderBook);
                throw new ServiceException("系统错误");
            }
        });
    }

    @Override
    @Transactional
    public void removeOrder(List<Long> ids) {

        ids.forEach(id -> {
            // 判断订单是否存在
            LambdaQueryWrapper<ObsOrder> orderExistWrapper = new LambdaQueryWrapper<ObsOrder>()
                    .select(ObsOrder::getOrderId)
                    .eq(ObsOrder::getOrderId, id);
            if (!orderMapper.exists(orderExistWrapper)) {
                throw new ServiceException("订单不存在");
            }
        });

        // 移除订单表数据
        int removeOrder = orderMapper.deleteBatchIds(ids);
        if (removeOrder <= 0) {
            log.error("数据库未知：{} = orderMapper.deleteBatchIds()", removeOrder);
            throw new ServiceException("系统错误");
        }

        // 移除订单书籍关联表的数据
        LambdaUpdateWrapper<ObsOrderBook> removeOrderBookWrapper = new LambdaUpdateWrapper<ObsOrderBook>()
                .in(ObsOrderBook::getOrderId, ids);
        int removeOrderBook = orderBookMapper.delete(removeOrderBookWrapper);
        if (removeOrderBook <= 0) {
            log.error("数据库未知：{} = orderMapper.delete()", removeOrderBook);
            throw new ServiceException("系统错误");
        }

    }

    @Override
    @Transactional
    public void updateOrder(ObsOrderUpdateDTO orderUpdateDTO) {

        ObsOrder obsOrder = new ObsOrder();

        Long orderId = orderUpdateDTO.getOrderId();
        Long userId = orderUpdateDTO.getUserId();
        Long addressId = orderUpdateDTO.getAddressId();
        OrderStatus orderStatus = orderUpdateDTO.getOrderStatus();
        List<ObsOrderBookAddDTO> bookList = orderUpdateDTO.getBookList();

        // 判断订单是否存在
        LambdaQueryWrapper<ObsOrder> orderExistWrapper = new LambdaQueryWrapper<ObsOrder>()
                .select(ObsOrder::getOrderId)
                .eq(ObsOrder::getOrderId, orderId);
        if (!orderMapper.exists(orderExistWrapper)) {
            throw new ServiceException("订单不存在");
        }

        // 判断用户是否存在
        userIsExist(userId);

        // 从DTO中获取订单数据
        BeanUtils.copyProperties(orderUpdateDTO, obsOrder);

        // 获取订单总价
        Double orderPrice = calculateOrderPrice(bookList);
        obsOrder.setOrderPrice(orderPrice);

        // 获取地址信息
        ObsAddress address = getAddress(addressId, userId);
        String newAddress = address.getAddress();
        String addressContact = address.getAddressContact();
        String addressDetail = address.getAddressDetail();
        String addressPhone = address.getAddressPhone();

        // 设置更新字段
        LambdaUpdateWrapper<ObsOrder> updateOrderWrapper = new LambdaUpdateWrapper<ObsOrder>()
                .set(ObsOrder::getUserId, userId)
                .set(ObsOrder::getOrderStatus, orderStatus)
                .set(ObsOrder::getOrderPrice, orderPrice)
                .set(ObsOrder::getAddress, newAddress)
                .set(ObsOrder::getAddressContact, addressContact)
                .set(ObsOrder::getAddressDetail, addressDetail)
                .set(ObsOrder::getAddressPhone, addressPhone)
                .eq(ObsOrder::getOrderId, orderId);

        int updateOrder = orderMapper.update(new ObsOrder(), updateOrderWrapper);
        if (updateOrder != 1) {
            log.error("数据库未知：{} = orderMapper.update({})", updateOrder, updateOrderWrapper.getSqlSet());
            throw new ServiceException("系统错误");
        }

        // 移除订单书籍关联表的数据
        LambdaUpdateWrapper<ObsOrderBook> removeOrderBookWrapper = new LambdaUpdateWrapper<ObsOrderBook>()
                .eq(ObsOrderBook::getOrderId, orderId);
        int removeOrderBook = orderBookMapper.delete(removeOrderBookWrapper);
        if (removeOrderBook <= 0) {
            log.error("数据库未知：{} = orderMapper.delete()", removeOrderBook);
            throw new ServiceException("系统错误");
        }

        // 重新添加数据
        bookList.forEach(bookDTO -> {
            // 创建订单书籍关联实体,并添加数据
            ObsOrderBook orderBook = new ObsOrderBook();
            BeanUtils.copyProperties(bookDTO, orderBook);
            orderBook.setOrderId(orderId);

            // 添加订单书籍关联表记录
            int insertOrderBook = orderBookMapper.insert(orderBook);
            if (insertOrderBook != 1) {
                log.error("数据库未知：{} = orderBookMapper.insert({})", insertOrderBook, orderBook);
                throw new ServiceException("系统错误");
            }
        });
    }

    /**
     * 判断用户是否存在
     *
     * @param userId 用户id
     */
    public void userIsExist(Long userId) {
        // 判断用户是否存在
        LambdaQueryWrapper<ObsUser> userExistWrapper = new LambdaQueryWrapper<ObsUser>()
                .select(ObsUser::getUserId)
                .eq(ObsUser::getUserId, userId);

        if (!userMapper.exists(userExistWrapper)) {
            throw new ServiceException("用户不存在");
        }
    }

    /**
     * 计算订单总价
     *
     * @param bookList 书籍集合
     * @return 订单总价
     */
    public Double calculateOrderPrice(List<ObsOrderBookAddDTO> bookList) {

        double price = 0.0;
        for (ObsOrderBookAddDTO bookDTO : bookList) {
            Long bookId = bookDTO.getBookId();
            Integer bookCount = bookDTO.getBookCount();

            // 检查书籍是否存在,存在则获取书籍信息
            ObsBook book = bookMapper.selectById(bookId);
            if (ObjectUtils.isNull(book)) {
                throw new ServiceException("书籍不存在！");
            }
            // 计算订单总价
            Double bookPrice = book.getBookPrice();
            price += bookPrice * bookCount;
        }
        // 格式化总价,保留两位小数
        BigDecimal decimal = new BigDecimal(price);
        return decimal.setScale(2, RoundingMode.HALF_UP).doubleValue();
    }

    /**
     * 获取收货地址信息
     *
     * @param addressId 地址id
     * @param userId    用户id
     * @return 地址信息
     */
    public ObsAddress getAddress(Long addressId, Long userId) {

        // 检查地址是否存在,存在则获取地址信息
        ObsAddress address;
        address = addressMapper.selectById(addressId);
        if (ObjectUtils.isNull(address)) {
            // 如果传入的地址不存在,则检查用户的默认地址是否存在
            LambdaQueryWrapper<ObsAddress> getAddressWrapper = new LambdaQueryWrapper<ObsAddress>()
                    .eq(ObsAddress::getUserId, userId)
                    .eq(ObsAddress::getAddressStatus, AddressStatus.IsDefault.getValue());
            // 如果存在则使用默认地址
            address = addressMapper.selectOne(getAddressWrapper);
            if (ObjectUtils.isNull(address)) {
                throw new ServiceException("地址不存在");
            }
        }
        return address;
    }
}
